package MyGui;

import java.awt.*;
import java.awt.event.*;
import java.awt.event.WindowEvent;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.table.*;
import java.util.Vector;

import DistSys.*;
import Element.AbsElem;

public class EditShadingDlg extends MyDlgFrame implements ActionListener,
                                                          WindowListener
{
    private Vector vSO = new Vector();

    private ShadingTableModel modelShading;
    private JTable            tblShading;

    private JButton btnRefresh, btnAdd, btnDelete, btnUp, btnDown;

    public EditShadingDlg(MainFrame parent, String title) {
        super(parent, title);

        updateContent();

        Container contentPane = getContentPane();
        contentPane.setLayout(gridBagLayout);

        modelShading = new ShadingTableModel();
        tblShading = new ShadingTable(modelShading);
        if (vSO.size() > 0)
            tblShading.changeSelection(0, 0, false, false);

        JLabel lblR = new JLabel("R : Result source");
        JLabel lblC = new JLabel("C : Continuous shading");
        JLabel lblA = new JLabel("A : Automatic scaling");
        lblR.setFont(GuiConst.fontDefault);
        lblC.setFont(GuiConst.fontDefault);
        lblA.setFont(GuiConst.fontDefault);

        btnRefresh = new JButton("Refresh Screen");
        btnRefresh.addActionListener(this);
        btnAdd = new JButton("Add");
        btnAdd.addActionListener(this);
        btnDelete = new JButton("Delete");
        btnDelete.addActionListener(this);
        btnUp = new JButton("Up");
        btnUp.addActionListener(this);
        btnDown = new JButton("Down");
        btnDown.addActionListener(this);

        GridBagConstraints c = new GridBagConstraints();
        c.insets = new Insets(GAP, GAP, GAP, GAP);
        c.gridwidth = 6; c.weightx = 1; c.weighty = 1;
        c.fill = GridBagConstraints.BOTH;
        contentPane.add(new JScrollPane(tblShading), c);

        c.insets.top = c.insets.bottom = c.insets.right = 0;
        c.gridwidth = 1; c.weightx = 0; c.weighty = 0;
        c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST;
        c.gridy = 1; contentPane.add(lblR, c);
        c.gridy = 2; contentPane.add(lblC, c);
        c.gridy = 3; contentPane.add(lblA, c);

        c.gridx = 1; c.gridy = 1; c.gridheight = 3; c.weightx = 1;
        c.anchor = GridBagConstraints.CENTER;
        contentPane.add(btnRefresh, c);

        c.gridx = 2; c.weightx = 0; contentPane.add(btnAdd, c);
        c.gridx = 3; contentPane.add(btnDelete, c);
        c.gridx = 4; contentPane.add(btnUp, c);
        c.insets.right = GAP;
        c.gridx = 5; contentPane.add(btnDown, c);

        this.addWindowListener(this);
        this.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
        this.setSize(620,350);
        this.setLocation(200,200);
        //this.setResizable(false);
        //this.show();
    }

    private class ShadingTable extends JTable {
        final int[] columnWidths = {
            125,   // 0 Label
            18,    // 1 IsResult
            160,   // 2 Source
            18,    // 3 Continuous
            18,    // 4 AutoScale
            55,    // 5 Percent Below
            55,    // 6 Percent Above
            65,    // 7 Start Value
            65,    // 8 End Value
        };

        public ShadingTable(TableModel model) {
            super(model);

            setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
            setFont(GuiConst.fontDefault);
            setDefaultRenderer( Integer.class, new IndexRenderer());
            setDefaultEditor( Integer.class, new IndexEditor());
            setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            TableColumnModel colModel = getColumnModel();
            for (int i = 0; i < columnWidths.length; i++)
                colModel.getColumn(i).setPreferredWidth(columnWidths[i]);

            // set ClickCountToStart
            TableCellEditor editor = getDefaultEditor(String.class);
            if (editor instanceof DefaultCellEditor)
                ((DefaultCellEditor)editor).setClickCountToStart(1);
            editor = getDefaultEditor(Double.class);
            if (editor instanceof DefaultCellEditor)
                ((DefaultCellEditor)editor).setClickCountToStart(1);
        }

        public String getToolTipText(MouseEvent event) {
            // Locate the cell under the event location
            Point p = event.getPoint();
            int hitColumnIndex = columnAtPoint(p);
            int hitRowIndex = rowAtPoint(p);

            if ((hitColumnIndex != -1) && (hitRowIndex != -1)) {
                ShadingOption so = (ShadingOption)vSO.elementAt(hitRowIndex);
                int iModelColumn = convertColumnIndexToModel(hitColumnIndex);
                switch (iModelColumn) {
                    case 0: return "label";
                    case 1: return "source is a result field if selected; " +
                                   "a data field otherwise";
                    case 2: if (so.getIsResult())
                                return "source: result field";
                            else return "source: data field";
                    case 3: return "continuous shading if selected; " +
                                   "discrete shading otherwise";
                    case 4: return "start and end value are determined " +
                                   "automatically if selected";
                    case 5:
                    case 6: if (!so.getAutoScale())
                                return "only valid if automatic scaling is " +
                                       "selected";
                            else if (iModelColumn == 5)
                                return "% of components below the start value";
                            else return "% of components above the end value";
                    case 7:
                    case 8: if (so.getAutoScale())
                                return "only valid if automatic scaling is " +
                                       "not selected";
                            else if (iModelColumn == 7)
                                return "start value";
                            else return "end value";
                }
            }

            // No tip from us ask our super class
            return super.getToolTipText(event);
        }
    };//end of ShadingTable

    private class ShadingTableModel extends AbstractTableModel {
        final String[] columnNames = {
            "Label",       // 0
            "R",           // 1
            "Source",      // 2
            "C",           // 3
            "A",           // 4
            "% Below",     // 5
            "% Above",     // 6
            "Start Value", // 7
            "End Value"    // 8
        };
        final Class[] columnClasses = {
            String.class,               // 0 Label
            Boolean.class,              // 1 IsResult
            Integer.class,              // 2 Source
            Boolean.class,              // 3 Continuous
            Boolean.class,              // 4 AutoScale
            Double.class,               // 5 Percent Below
            Double.class,               // 6 Percent Above
            Double.class,               // 7 Start Value
            Double.class                // 8 End Value
        };

        public int getColumnCount() { return columnNames.length; }
        public int getRowCount() { return vSO.size(); }
        public String getColumnName(int col) { return columnNames[col]; }
        public Class getColumnClass(int col) { return columnClasses[col]; }
        public Object getValueAt(int row, int col) {
            ShadingOption so = (ShadingOption)vSO.elementAt(row);
            switch (col) {
                case 0: return so.getDescription();
                case 1: return new Boolean(so.getIsResult());
                case 2: return new Integer(so.getIndex());
                case 3: return new Boolean(so.getContinuous());
                case 4: return new Boolean(so.getAutoScale());
                case 5: if (so.getAutoScale())
                            return new Double(so.getPercentBelow());
                        else return null;
                case 6: if (so.getAutoScale())
                            return new Double(so.getPercentAbove());
                        else return null;
                case 7: if (!so.getAutoScale())
                            return new Double(so.getStartValue());
                        else return null;
                case 8: if (!so.getAutoScale())
                            return new Double(so.getEndValue());
                        else return null;
                default: return null;
            }
        }

        public boolean isCellEditable(int row, int col) {
            if (col <= 4)
                return true;
            else {
                boolean b = ((ShadingOption)vSO.elementAt(row)).getAutoScale();
                if (col <= 6) return b;
                else return !b;
            }
        }

        public void setValueAt(Object value, int row, int col) {
            ShadingOption so = (ShadingOption)vSO.elementAt(row);
            String sText;
            switch (col) {
                case 0:
                    so.setDescription((String)value);
                    break;
                case 1:
                    // set IsResult
                    boolean bIsResult = ((Boolean)value).booleanValue();
                    so.setIsResult(bIsResult);
                    // check index range and set description
                    if (bIsResult) {
                        if (so.getIndex() >= AbsElem.NUM_RES_FIELD)
                            so.setIndex(AbsElem.NUM_RES_FIELD-1);
                        sText = SysConst.getResultFieldFromValueIndex(
                            so.getIndex());
                    } else {
                        if (so.getIndex() >= AbsElem.NUM_DATA_FIELD)
                            so.setIndex(AbsElem.NUM_DATA_FIELD-1);
                        sText = SysConst.getDataFieldFromValueIndex(
                            so.getIndex());
                    }
                    so.setDescription(sText);
                    break;
                case 2:
                    int iValue = ((Integer)value).intValue();
                    if (iValue != so.getIndex()) {
                        so.setIndex(iValue);
                        if (so.getIsResult())
                            sText=SysConst.getResultFieldFromValueIndex(iValue);
                        else
                            sText = SysConst.getDataFieldFromValueIndex(iValue);
                        so.setDescription(sText);
                    }
                    break;
                case 3:
                    so.setContinuous(((Boolean)value).booleanValue());
                    break;
                case 4:
                    so.setAutoScale(((Boolean)value).booleanValue());
                    break;
                case 5:
                case 6:
                    double dValue = ((Double)value).doubleValue();
                    if (dValue >= 0.0 && dValue <= 100.0) {
                        if (col == 5)
                            so.setPercentBelow(dValue);
                        else
                            so.setPercentAbove(dValue);
                    } else {
                        JOptionPane.showMessageDialog(null, "'" + dValue +
                            "' is not a valid percentage value.", "Error",
                            JOptionPane.ERROR_MESSAGE);
                    }
                    break;
                case 7:
                    so.setStartValue(((Double)value).doubleValue());
                    break;
                case 8:
                    so.setEndValue(((Double)value).doubleValue());
                    break;
            }
            fireTableRowsUpdated(row, row);
        }
    }//end of class ShadingTableModel


    private class IndexRenderer extends DefaultTableCellRenderer {
        boolean bIsResult;
        public Component getTableCellRendererComponent(JTable table, Object val,
            boolean isSelected, boolean hasFocus, int row, int column) {
            // Are we editing a result or a data field?
            bIsResult = ((ShadingOption)vSO.elementAt(row)).getIsResult();
            return super.getTableCellRendererComponent(table, val, isSelected,
                hasFocus, row, column);
        }
        public void setValue(Object value) {
            int iValue = ((Integer)value).intValue();
            String sText;
            if (bIsResult)
                sText = SysConst.getResultFieldFromValueIndex(iValue);
            else
                sText = SysConst.getDataFieldFromValueIndex(iValue);
            setText(sText);
        }
    }//end of class IndexRenderer

    private class IndexEditor extends AbstractCellEditor
                                    implements TableCellEditor {
        boolean bIsResult;
        JComboBox comboBox = new JComboBox();

        public Component getTableCellEditorComponent(JTable table, Object value,
                                                     boolean isSelected,
                                                     int row, int column) {
            comboBox.setFont(table.getFont());
            // Are we editing a result or a data field?
            bIsResult = ((ShadingOption)vSO.elementAt(row)).getIsResult();
            // Fill the combo box
            int iValue = ((Integer)value).intValue();
            int iIndexDisplay;
            if (bIsResult) {
                comboBox.setModel(new DefaultComboBoxModel(SysConst.ssResultField));
                iIndexDisplay = SysConst.mapResultIndexFromValueToDisplay(iValue);
            } else {
                comboBox.setModel(new DefaultComboBoxModel(SysConst.ssDataField));
                iIndexDisplay = SysConst.mapDataIndexFromValueToDisplay(iValue);
            }
            comboBox.setSelectedIndex( iIndexDisplay );
            return comboBox;
        }

        public Object getCellEditorValue() {
            int iIndexDisplay = comboBox.getSelectedIndex();
            int iValue;
            if (bIsResult)
                iValue = SysConst.mapResultIndexFromDisplayToValue(iIndexDisplay);
            else
                iValue = SysConst.mapDataIndexFromDisplayToValue(iIndexDisplay);
            return new Integer(iValue);
        }
    }//end of class IndexEditor

    public void updateContent() {
        int iCount = Sys.prjInfo.storedShadingOptions.size();
        vSO.setSize(iCount);
        for (int i = 0; i < iCount; i++) {
            ShadingOption so = new ShadingOption();
            so.copyFrom((ShadingOption)Sys.prjInfo.storedShadingOptions.
                elementAt(i));
            vSO.setElementAt(so, i);
        }
    }

    private boolean refresh(){
        // If we are currently editing,
        // we should save the value and stop editing
        if (tblShading.isEditing() &&
            !tblShading.getCellEditor().stopCellEditing())
            return false;

        // save shading options
        int iCount = vSO.size();
        Sys.prjInfo.storedShadingOptions.setSize(iCount);
        for (int i = 0; i < iCount; i++) {
            ShadingOption so = new ShadingOption();
            so.copyFrom((ShadingOption)vSO.elementAt(i));
            Sys.prjInfo.storedShadingOptions.setElementAt(so, i);
        }

        // update screen
        int iRow = tblShading.getSelectedRow();
        mainFrame.menuBar.setCurrentShadingOption(
            (iRow >= 0 ? iRow : Sys.prjInfo.shadingCat));
        mainFrame.menuBar.setShadeMenuText();
        mainFrame.mainPanel.setNeedRedraw(true);
        mainFrame.mainPanel.repaint();
        return true;
    }

    /*======================================
      Implement WindowListener interfaces
    ======================================*/
    public void windowOpened( WindowEvent evt ){ }
    public void windowClosed( WindowEvent evt ){ }
    public void windowIconified( WindowEvent evt ){ }
    public void windowDeiconified( WindowEvent evt ){ }
    public void windowActivated( WindowEvent evt ){ }
    public void windowDeactivated( WindowEvent evt ){ }
    public void windowClosing( WindowEvent evt ){
        if (refresh())
            hide();
    }

    public void actionPerformed(ActionEvent evt){
        Object src = evt.getSource();
        // If we are currently editing,
        // we should save the value and stop editing
        if (tblShading.isEditing())
            tblShading.getCellEditor().stopCellEditing();
        if (src == btnRefresh) {
            refresh();
        } else if (src == btnAdd) {
            int iRow = vSO.size();
            vSO.addElement(new ShadingOption());
            modelShading.fireTableRowsInserted(iRow, iRow);
            tblShading.changeSelection(iRow, 0, false, false);
        } else {
            int iRow = tblShading.getSelectedRow();
            int iCol = tblShading.getSelectedColumn();
            if (src == btnDelete) {
                if (iRow >= 0) {
                    vSO.removeElementAt(iRow);
                    modelShading.fireTableRowsDeleted(iRow, iRow);
                    if (iRow == vSO.size())
                        tblShading.changeSelection(iRow-1, iCol, false, false);
                    else
                        tblShading.changeSelection(iRow, iCol, false, false);
                }
            } else if (src == btnUp) {
                if (iRow >= 1) {
                    Object shadingOption = vSO.elementAt(iRow);
                    vSO.setElementAt(vSO.elementAt(iRow-1), iRow);
                    vSO.setElementAt(shadingOption, iRow-1);
                    modelShading.fireTableRowsUpdated(iRow-1, iRow);
                    tblShading.changeSelection(iRow-1, iCol, false, false);
                }
            } else if (src == btnDown) {
                if (iRow >= 0 && iRow < vSO.size()-1) {
                    Object shadingOption = vSO.elementAt(iRow);
                    vSO.setElementAt(vSO.elementAt(iRow+1), iRow);
                    vSO.setElementAt(shadingOption, iRow+1);
                    modelShading.fireTableRowsUpdated(iRow, iRow+1);
                    tblShading.changeSelection(iRow+1, iCol, false, false);
                }
            }
        }
    }
}